package com.tyylab.kestrel.plugins.nacos.sharens.config.properties;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.client.naming.utils.UtilAndComs;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;

import static com.alibaba.nacos.api.PropertyKeyConst.*;
import static java.util.Objects.nonNull;
@Slf4j
public class KestrelNacosShareDicoveryProperties {

    NacosShareProperties nacosShareProperties;
    NacosDiscoveryProperties nacosDiscoveryProperties;

    private Map<String, NamingService> namespace_2_namingservice_map = new ConcurrentHashMap<>();


    public KestrelNacosShareDicoveryProperties(NacosShareProperties nacosShareProperties, NacosDiscoveryProperties nacosDiscoveryProperties) {
        this.nacosShareProperties = nacosShareProperties;
        this.nacosDiscoveryProperties = nacosDiscoveryProperties;
    }

    public Map<String, NamingService> shareNamingServiceInstances() {
        if (!namespace_2_namingservice_map.isEmpty()) {
            return new HashMap<>(namespace_2_namingservice_map);
        }
        List<NacosShareProperties.NacosShareEntity> entities = Optional.ofNullable(nacosShareProperties)
                .map(NacosShareProperties::getEntities).orElse(Collections.emptyList());
        entities.stream().filter(entity -> nonNull(entity) && nonNull(entity.getNamespace()))
                .filter(distinctByKey(NacosShareProperties.NacosShareEntity::getNamespace))
                .forEach(entity -> {
                    try {
                        NamingService namingService = NacosFactory.createNamingService(getNacosProperties(entity.getNamespace()));
                        if (namingService != null) {
                            namespace_2_namingservice_map.put(entity.getNamespace(), namingService);
                        }
                    } catch (Exception e) {
                        log.error("create naming service error! properties={}, e=", this, e);
                    }
                });
        return new HashMap<>(namespace_2_namingservice_map);
    }
    static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object,Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    private Properties getNacosProperties(String namespace) {
        Properties properties = new Properties();
        properties.put(SERVER_ADDR, nacosDiscoveryProperties.getServerAddr());
        properties.put(USERNAME, Objects.toString(nacosDiscoveryProperties.getUsername(), ""));
        properties.put(PASSWORD, Objects.toString(nacosDiscoveryProperties.getPassword(), ""));
        properties.put(NAMESPACE, namespace);
        properties.put(UtilAndComs.NACOS_NAMING_LOG_NAME, nacosDiscoveryProperties.getLogName());
        String endpoint = nacosDiscoveryProperties.getEndpoint();
        if (endpoint.contains(":")) {
            int index = endpoint.indexOf(":");
            properties.put(ENDPOINT, endpoint.substring(0, index));
            properties.put(ENDPOINT_PORT, endpoint.substring(index + 1));
        }
        else {
            properties.put(ENDPOINT, endpoint);
        }

        properties.put(ACCESS_KEY, nacosDiscoveryProperties.getAccessKey());
        properties.put(SECRET_KEY, nacosDiscoveryProperties.getSecretKey());
        properties.put(CLUSTER_NAME, nacosDiscoveryProperties.getClusterName());
        properties.put(NAMING_LOAD_CACHE_AT_START, nacosDiscoveryProperties.getNamingLoadCacheAtStart());

//        enrichNacosDiscoveryProperties(properties);
        return properties;
    }

}
